package com.ft.oa.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ft.oa.constant.SysUserExceptionConstant;
import com.ft.oa.domain.dto.ApiResult;
import com.ft.oa.domain.dto.condition.SysUserDTO;
import com.ft.oa.domain.dto.sys.SecurityUser;
import com.ft.oa.domain.sys.*;
import com.ft.oa.mapper.sys.SysUserDeptMapper;
import com.ft.oa.mapper.sys.SysUserMapper;
import com.ft.oa.mapper.sys.SysUserRoleMapper;
import com.ft.oa.security.constant.SecurityConstant;
import com.ft.oa.service.sys.SysAuthService;
import com.ft.oa.service.sys.SysDeptService;
import com.ft.oa.service.sys.SysRoleService;
import com.ft.oa.service.sys.SysUserService;
import com.ft.oa.utils.SecurityUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SysUserServiceImpl implements SysUserService {

    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private SysUserDeptMapper sysUserDeptMapper;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private SysDeptService sysDeptService;
    @Resource
    private SysAuthService sysAuthService;


    @Override
    public SysUser info() {
        SecurityUser currentUser = SecurityUtils.getCurrentUser();
        SysUser sysUser = sysUserMapper.selectById(currentUser.getId());
        List<SysDept> sysDepts = sysDeptService.userDepts(sysUser.getId());
        sysUser.setDepts(sysDepts);
        sysUser.setPassword("");
        return sysUser;
    }

    @Override
    public SecurityUser loadByUsername(String username) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysUser::getUsername, username)
                .eq(SysUser::getDel, false)
                .eq(SysUser::getEnable, true);
        SysUser sysUser = sysUserMapper.selectOne(wrapper);
        if(Objects.nonNull(sysUser)){
            //用户角色
            SecurityUser securityUser = new SecurityUser(sysUser);
            if(sysUser.getId() == 1){
                securityUser.setRoles(SecurityConstant.SUPER_ROLE_SET);
                return securityUser;
            }
            List<SysRole> roles = userRoles(sysUser.getId());
            Set<String> roleNames = roles.stream().map(SysRole::getName).collect(Collectors.toSet());
            securityUser.setRoles(roleNames);
            //用户权限
            List<SysAuth> authList = roleAuths(roles.stream().map(SysRole::getId).collect(Collectors.toSet()));
            Set<String> auths = authList.stream().map(SysAuth::getUrl).filter(StringUtils::hasText).collect(Collectors.toSet());
            String[] a = {};
            List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(auths.toArray(a));
            securityUser.setAuthorities(authorityList);
            //增加数据权限（目前设计一个人只有一个角色）
            if(roles!=null&&roles.size()>0){
                securityUser.setManager(roles.get(0).getManager());
            }
            return securityUser;
        }else {
            return null;
        }

    }

    @Override
    public List<SysRole> userRoles(Long uid) {
        List<SysRole> roles = sysRoleService.userRoles(uid);

        return roles;
    }

    @Override
    public List<SysAuth> roleAuths(Set<Integer> roleIds) {

        List<SysAuth> authList = sysAuthService.roleAuths(roleIds);
        return authList;
    }

    @Override
    public List<SysUser> listAll() {

        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysUser::getDel, false)
                .eq(SysUser::getEnable, true);

        List<SysUser> sysUsers = sysUserMapper.selectList(wrapper);
        sysUsers.forEach(e->e.setPassword(""));
        return sysUsers;
    }

    @Override
    @Transactional
    public ApiResult add(SysUserDTO user) {
        //新增用户
        //用户名查重
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysUser::getDel, false)
                .eq(SysUser::getUsername, user.getUsername());

        SysUser sysUser = sysUserMapper.selectOne(wrapper);

        if(sysUser != null){
            return ApiResult.builder()
                    .code(SysUserExceptionConstant.USERNAME_ALREADY_HAVE)
                    .msg("用户名已被使用!")
                    .build();
        }

        SysUser save = new SysUser(user);
        LocalDateTime now = LocalDateTime.now();
        save.setPassword(passwordEncoder.encode(save.getPassword()));
        save.setCreateTime(now);
        sysUserMapper.insert(save);

        //保存角色
        updateUserRoles(save.getId(), user.getRoles());
        //保存部门
        updateUserDepts(save.getId(), user.getDepts());

        return ApiResult.simpleSuccess();
    }

    @Override
    @Transactional
    public ApiResult edit(SysUserDTO user) {
        //用户名查重
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysUser::getDel, false)
                .eq(SysUser::getUsername, user.getUsername());
        SysUser sysUser = sysUserMapper.selectOne(wrapper);
        if(sysUser != null && ! user.getUsername().equals(sysUser.getUsername()) ){
            return ApiResult.builder()
                    .code(SysUserExceptionConstant.USERNAME_ALREADY_HAVE)
                    .msg("用户名已被使用!")
                    .build();
        }
        SysUser save = new SysUser(user);
        save.setUpdateTime(LocalDateTime.now());
        save.setPassword(passwordEncoder.encode(save.getPassword()));
        int i = sysUserMapper.updateById(save);
        //保存角色
        updateUserRoles(save.getId(), user.getRoles());
        //保存部门
        updateUserDepts(save.getId(), user.getDepts());
        return ApiResult.simpleSuccess();
    }

    @Override
    @Transactional
    public void del(Long id) {
        LambdaUpdateChainWrapper<SysUser> wrapper = new LambdaUpdateChainWrapper<>(sysUserMapper);
        LocalDateTime now = LocalDateTime.now();
        boolean update = wrapper.eq(SysUser::getId, id)
                .set(SysUser::getDel, true)
                .set(SysUser::getDeleteTime, now)
                .set(SysUser::getUpdateTime, now)
                .update();
    }

    @Override
    @Transactional
    public void updateUserRoles(Long userId, Set<Integer> roleIds) {
        QueryWrapper<SysUserRole> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        int delete = sysUserRoleMapper.delete(wrapper);

        roleIds.stream()
                .map(roleId -> new SysUserRole(userId, roleId))
                .forEach(e -> sysUserRoleMapper.insert(e));

    }

    @Override
    @Transactional
    public void updateUserDepts(Long userId, Set<Integer> deptIds) {
        QueryWrapper<SysUserDept> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        int delete = sysUserDeptMapper.delete(wrapper);

        deptIds.stream()
                .map(deptId -> new SysUserDept(userId, deptId))
                .forEach(e -> sysUserDeptMapper.insert(e));

    }

    @Override
    public Page<SysUser> page(SysUserDTO user, int page, int size) {

        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("create_time");
        wrapper.lambda()
                .ne(SysUser::getUsername,"admin")
                .likeRight(StringUtils.hasText(user.getNickname()),SysUser::getNickname, user.getNickname())
                .eq(SysUser::getDel, false);

        Page<SysUser> pageCondition = new Page<>(page, size);
        Page<SysUser> sysUserPage = sysUserMapper.selectPage(pageCondition, wrapper);
        if(sysUserPage.getTotal() != 0){
            sysUserPage.getRecords()
                    .forEach(e-> {
                        e.setPassword("");
                        List<SysRole> roles = sysRoleService.userRoles(e.getId());
                        e.setRoles(roles);
                        e.setRoleNames(roles.stream().map(SysRole::getName).collect(Collectors.joining(",")));
                        List<SysDept> depts = sysDeptService.userDepts(e.getId());
                        e.setDepts(depts);
                    });
        }
        return sysUserPage;
    }
}
